package handlers

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"

	"grpc-jwt-yonghurenzheng/v1.0_session_cookies/config"
	"grpc-jwt-yonghurenzheng/v1.0_session_cookies/models"

	"golang.org/x/crypto/bcrypt"
)

// 注册
func Register(w http.ResponseWriter, r *http.Request) {
	var user models.User
	if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
		http.Error(w, "请求数据错误", http.StatusBadRequest)
		return
	}

	// 密码加密
	hashed, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
	if err != nil {
		http.Error(w, "密码加密失败", http.StatusInternalServerError)
		return
	}

	// 插入数据库
	_, err = config.DB.Exec("INSERT INTO users (username, password, email) VALUES (?, ?, ?)",
		user.Username, string(hashed), user.Email)
	if err != nil {
		http.Error(w, fmt.Sprintf("注册失败: %v", err), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(map[string]string{"message": "注册成功"})
}

// 统一 JSON 错误返回
func writeJSONError(w http.ResponseWriter, status int, msg string) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    json.NewEncoder(w).Encode(map[string]string{"error": msg})
}

// Login 登录接口
func Login(w http.ResponseWriter, r *http.Request) {
    // 只允许 POST
    if r.Method != http.MethodPost {
        writeJSONError(w, http.StatusMethodNotAllowed, "只允许 POST 方法")
        return
    }

    w.Header().Set("Content-Type", "application/json")

    // 解析请求 JSON
    var loginReq models.User
    if err := json.NewDecoder(r.Body).Decode(&loginReq); err != nil {
        writeJSONError(w, http.StatusBadRequest, "请求 JSON 数据错误: " + err.Error())
        return
    }

    if loginReq.Username == "" || loginReq.Password == "" {
        writeJSONError(w, http.StatusBadRequest, "用户名或密码不能为空")
        return
    }

    // 从数据库查询用户
    var user models.User
    var hashedPwd string
    err := config.DB.QueryRow("SELECT id, username, password, email FROM users WHERE username = ?", loginReq.Username).
        Scan(&user.ID, &user.Username, &hashedPwd, &user.Email)

    if err == sql.ErrNoRows {
        writeJSONError(w, http.StatusUnauthorized, "用户不存在")
        return
    } else if err != nil {
        writeJSONError(w, http.StatusInternalServerError, "查询数据库失败: "+err.Error())
        return
    }

    // 校验密码
    if err := bcrypt.CompareHashAndPassword([]byte(hashedPwd), []byte(loginReq.Password)); err != nil {
        writeJSONError(w, http.StatusUnauthorized, "密码错误")
        return
    }

    	// --- Session 核心逻辑 ---
	// 1. 从请求中获取或创建一个 session
	session, err := config.Store.Get(r, "user-session")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// 2. 设置 session 值
	session.Values["user_id"] = user.ID
	session.Values["username"] = user.Username
	session.Values["authenticated"] = true

	// 3. 保存 session，这会通过 Set-Cookie 头将会话ID写入客户端浏览器
	if err := session.Save(r, w); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// --- Session 核心逻辑结束 ---

	json.NewEncoder(w).Encode(map[string]interface{}{
		"message":  "登录成功",
		"user_id":  user.ID,
		"username": user.Username,
	})
}

// Logout 登出接口
func Logout(w http.ResponseWriter, r *http.Request) {
	session, err := config.Store.Get(r, "user-session")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 将认证状态设为 false 并立即过期 cookie
	session.Values["authenticated"] = false
	session.Options.MaxAge = -1 

	if err := session.Save(r, w); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	json.NewEncoder(w).Encode(map[string]string{"message": "已成功登出"})
}


// Profile 获取用户信息接口 (需要认证)
func Profile(w http.ResponseWriter, r *http.Request) {
	session, err := config.Store.Get(r, "user-session")
	if err != nil {
		writeJSONError(w, http.StatusInternalServerError, "无法获取会话")
		return
	}

	// 检查认证状态
	if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
		writeJSONError(w, http.StatusUnauthorized, "未授权访问，请先登录")
		return
	}

	// 从 session 获取用户信息
	userID := session.Values["user_id"]
	username := session.Values["username"]

	json.NewEncoder(w).Encode(map[string]interface{}{
		"message":  "获取用户信息成功",
		"user_id":  userID,
		"username": username,
	})
}



// 注销用户
// func DeleteUser(w http.ResponseWriter, r *http.Request) {
//     var req struct {
//         Username string `json:"username"`
//     }

//     if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
//         http.Error(w, "请求数据错误", http.StatusBadRequest)
//         return
//     }

//     // 先查询用户是否存在
//     var userID int
//     err := config.DB.QueryRow("SELECT id FROM users WHERE username = ?", req.Username).Scan(&userID)
//     if err == sql.ErrNoRows {
//         http.Error(w, "用户不存在", http.StatusNotFound)
//         return
//     } else if err != nil {
//         http.Error(w, "查询数据库失败", http.StatusInternalServerError)
//         return
//     }

//     // 如果有外键表（比如 addresses），可先删除子表，或者保证外键 ON DELETE CASCADE
//     // 删除子表示例：
//     _, err = config.DB.Exec("DELETE FROM addresses WHERE user_id = ?", userID)
//     if err != nil {
//         http.Error(w, "删除用户地址失败", http.StatusInternalServerError)
//         return
//     }

//     // 删除用户
//     _, err = config.DB.Exec("DELETE FROM users WHERE id = ?", userID)
//     if err != nil {
//         http.Error(w, "删除用户失败", http.StatusInternalServerError)
//         return
//     }

//     json.NewEncoder(w).Encode(map[string]string{"message": "用户已注销"})
// }


// DeleteUser 删除当前登录的用户
func DeleteUser(w http.ResponseWriter, r *http.Request) {
    // 1. 检查会话，和 Profile 接口一样
	session, err := config.Store.Get(r, "user-session")
	if err != nil {
		writeJSONError(w, http.StatusInternalServerError, "无法获取会话")
		return
	}

	if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
		writeJSONError(w, http.StatusUnauthorized, "未授权访问，请先登录")
		return
	}

    // 2. 从 Session 中获取用户ID，而不是从请求Body中获取用户名
	userID, ok := session.Values["user_id"].(int64)
    if !ok {
        writeJSONError(w, http.StatusInternalServerError, "会话中用户ID无效")
		return
    }

	// 3. 执行删除操作 (假设您已设置外键级联删除或手动删除关联数据)
	_, err = config.DB.Exec("DELETE FROM users WHERE id = ?", userID)
	if err != nil {
		http.Error(w, "删除用户失败: "+err.Error(), http.StatusInternalServerError)
		return
	}

    // 4. 删除成功后，销毁会话（等同于强制登出）
    session.Options.MaxAge = -1
    session.Save(r, w)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]string{"message": "您的账户已成功注销"})
}